#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Game.h"

Game* Game_create(int mazeSizeX, int mazeSizeY, int playerCount) {
	Game* g = (Game*)malloc(sizeof(Game));

	//create maze
	(*g).maze = Maze_create(mazeSizeX, mazeSizeY);

	//create players
	(*g).playerCount = playerCount;
	(*g).players = (Player**)malloc(playerCount * sizeof(Player));
	for(int i = 0; i < playerCount; ++i) {
		(*g).players[i] = Player_create(0,0,'1'+i);
	}

	return g;
}

void Game_destroy(Game* game) {
	//destroy players
	for(int i = 0; i < (*game).playerCount; ++i) {
		Player_destroy((*game).players[i]);
	}
	free((*game).players);

	//destroy maze
	Maze_destroy((*game).maze);

	//destroy game
	free(game);
}

void Game_init(Game* game) {
	Maze_randomize((*game).maze);
	for(int i = 0; i < (*game).playerCount; ++i) {
		Game_randomizePlayerPosition(game, i);
	}
}

void Game_randomizePlayerPosition(Game* game, int playerIdx) {
	while(1) {
		int posX = rand() % (*(*game).maze).width;
		int posY = rand() % (*(*game).maze).height;
		if(Game_setPlayerPosition(game, playerIdx, posX, posY)) break;
	}
}

int Game_setPlayerPosition(Game* game, int playerIdx, int posX, int posY) {
	if(!Maze_isWalkable((*game).maze, posX, posY)) return 0;
	else {
		Player_setPosition((*game).players[playerIdx], posX, posY);
		return 1;
	}
}

int Game_movePlayerBy(Game* game, int playerIdx, int dx, int dy) {
	Player* p = (*game).players[playerIdx];
	return Game_setPlayerPosition(game, playerIdx, (*p).x + dx, (*p).y + dy);
}



//the graphics
#define GR_WALL		'+'
#define GR_WALKABLE	' '
#define GR_UNKNOWN	'O'

void Game_draw(Game* game, int left, int top, int width, int height, int playerIdx, int playerViewRadius) {
	//create framebuffer

	char* fb = (char*)malloc(width*height*sizeof(char));
	memset(fb, GR_UNKNOWN, width*height*sizeof(char));
	//
	Player* p = (*game).players[playerIdx];
	Maze* m = (*game).maze;

	for(int i = 0; i < playerViewRadius * 2; ++i) {
		for(int j = 0; j < playerViewRadius * 2; ++j) {
			//view check
			int viewX = (width >> 1) - playerViewRadius + i;
			int viewY = (height >> 1) - playerViewRadius + j;
			if(!(viewX >= 0 && viewX < width && viewY >= 0 && viewY < height)) continue;

			//diamond shaped tile visibility test
			int curX = (*p).x - playerViewRadius + i;
			int curY = (*p).y - playerViewRadius + j;
			int dx = curX - (*p).x; dx = dx < 0 ? -dx : dx;
			int dy = curY - (*p).y; dy = dy < 0 ? -dy : dy;
			if(dx + dy > playerViewRadius) continue;

			//we shouldn't draw any maze if the point to draw is out of bounds
			if(!Maze_isInBounds(m, curX, curY)) continue;
//			printf("%d %d %c\n",curX, curY, (*m).map[curY * (*m).width + curX]);
			fb[viewY * width + viewX] = (*m).map[curY * (*m).width + curX] == TILE_WALKABLE ? GR_WALKABLE : GR_WALL;
		}
//		printf("\n");
	}

	//draw players
	int viewX = (width >> 1);
	int viewY = (height >> 1);
	for(int i = 0; i < (*game).playerCount; ++i) {
		Player* pp = (*game).players[i];
		int dx = (*p).x - (*pp).x;
		int dy = (*p).y - (*pp).y;
		if((dx < 0 ? -dx : dx) + (dy < 0 ? -dy : dy) <= playerViewRadius) {
			fb[(viewY - dy) * width + (viewX - dx)] = (*pp).image;
		}
	}

	//draw me
	fb[(viewY) * width + (viewX)] = (*p).image;


	//Display it to screen
	system("clear");
	for(int j = 0; j < height; ++j) {
		for(int i = 0; i < width; ++i) {
			printf(" %c", fb[j * width + i]);
		}
		printf("\n");
	}

	//free temporaries
	free(fb);

	/*
	//calculate portion of maze that will be drawn to framebuffer
	int hw = width >> 1;
	int hh = height >> 1;
	int ol = (*p).x - hw; ol = ol < 0 ? 0 : -ol; //offset left
	int ot = (*p).y - hh; ot = ot < 0 ? 0 : -ot; //offset top
	int ml = (*p).x - hw; ml = ml < 0 ? 0 : ml; //maze's left
	int mt = (*p).y - hh; mt = mt < 0 ? 0 : mt; //maze's top
	int mr = (*p).x + hw; mr = mr >= (*m).width ? (*m).width - 1 : mr; //maze's right
	int mb = (*p).y + hh; mb = mb >= (*m).height ? (*m).height - 1 : mb; //maze's bottom

	//draw maze into framebuffer
	int i, j;
	for(i = 0; i < (*m).height; ++i) {
		for(j = 0; j < (*m).width; ++j) {
			printf(" %c", (*m).map[i*(*m).width + j]);
		}
		printf("\n");
	}
	*/
}
